﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Text;
using System.Threading;
using Fadd.Net;
using Xunit;

namespace Fadd.Test.Net
{
    public class BinaryTransportTest
    {
        private IPEndPoint _endPoint;

        public BinaryTransportTest()
        {
            _endPoint = new IPEndPoint(IPAddress.Loopback, 12344);
        }
        
        [Fact]
        public void TestNonSerializableObject()
        {
            SimpleServer server = new SimpleServer(_endPoint, (s) => {});
            server.Start(5);

            Assert.Throws(typeof (InvalidOperationException),
                          () => new BinaryTransport<NonSerializable>(_endPoint));

            server.Stop();
        }

        [Fact]
        public void TestReconnect()
        {
            int counter = 0;
            ManualResetEvent _trigger = new ManualResetEvent(false);

            Socket socket = null;
            SimpleServer server = new SimpleServer(_endPoint, (s) =>
                                                                  {
                                                                      socket = s;
                                                                      ++counter;
                                                                      _trigger.Set();
                                                                  });

            server.Start(5);

            var transport = new BinaryTransport<TestWrapper>(_endPoint);
            transport.Start();
            if (!_trigger.WaitOne(5000))
                Assert.True(false, "Failed to connect the first time.");
            _trigger.Reset();

            transport.ReconnectInterval = 500;
            socket.Close();
            if (!_trigger.WaitOne(1000))
                Assert.False(true, "Failed to reconnect in specified interval.");

            Assert.Equal(2, counter);
            server.Stop();
        }

        [Fact]
        public void TestNonSerializableChildObject()
        {
            SimpleServer server = new SimpleServer(_endPoint, (s) => { });
            server.Start(5);

            Assert.Throws(typeof(SerializationException),
                          () =>
                              {
                                  var channel = new BinaryTransport<TestWrapper>(_endPoint);
                                  channel.Send(new NonSerializable());
                              });

            server.Stop();
        }

        [Fact]
        public void TestNoObjectConstructor()
        {
            SimpleServer server = new SimpleServer(_endPoint, (s) => { });
            server.Start(5);
            Assert.Throws(typeof (InvalidOperationException),
                          () => new BinaryTransport<NoObjectConstructor>(_endPoint));
            
            server.Stop();
        }


        [Fact]
        public void TestSerializable()
        {
            SimpleServer server = new SimpleServer(_endPoint, (s) => { });
            server.Start(5);
            var channel = new BinaryTransport<TestWrapper>(_endPoint);
            channel.Send("Hello world");
            server.Stop();
        }
    }

    class NonSerializable
    {
        
    }

    [Serializable]
    class NoObjectConstructor
{
    
}


    [Serializable]
    class TestWrapper
    {
        public Object Child { get; set; }

        public TestWrapper(object value)
        {
            Child = value;
        }

        public TestWrapper()
        {
            
        }
    }
}
